`include "top.vh"

module wb_stage(
    input   wire clk           ,
    input   wire reset         ,
    //allowin
    output wire ws_allowin    ,
    //from ms
    input   wire    ms_to_ws_valid,
    input   wire [`ms_2_ws_bus_wid - 1:0]  ms_to_ws_bus  ,
    //to id
    output wire [38:0]  ws_to_id_bus  ,
    //trace debug interface
    output wire [31:0] debug_wb_pc        ,
    output wire [ 3:0] debug_wb_rf_we ,
    output wire [ 4:0] debug_wb_rf_wnum,
    output wire [31:0] debug_wb_rf_wdata,
    //csr read & write
    output wire [13:0] csr_num,
    input  wire [31:0] csr_rvalue,
    output wire        csr_we,
    output wire [31:0] csr_wvalue,
    output wire [31:0] csr_wmask,
    //csr data block
    output wire read_csr,
    //ex
    output wire ws_ex_out,
    output wire ws_ertn_flush,
    output wire [ 5:0] Ecode,
    output wire [ 8:0] EsubCode
);

reg         ws_valid;
wire        ws_ready_go;
reg [ 3:0] ws_sram_we;

wire ws_gr_we;
wire [ 4:0] ws_dest;
wire [31:0] ws_final_result;
wire [31:0] ws_pc;
wire ws_rf_we;
wire        rf_we;
wire [4 :0] rf_waddr;
wire [31:0] rf_wdata;

wire csrrd, csrwr, csrxchg;
wire [31:0] csr_wmask_temp;
wire [`CSR_SIG_wid-1:0] csr_signal;
wire ex, ertn;

assign read_csr = (csr_signal[80:78] != 3'b0) && ws_valid;
assign csr_we = csrwr | csrxchg;
assign csr_wmask = csrxchg ? csr_wmask_temp : 32'hffffffff;
assign {csrrd, csrwr, csrxchg, csr_num, csr_wvalue, csr_wmask_temp} = csr_signal;
assign ws_ertn_flush = ertn && ws_valid;
assign Ecode = ws_ex_out ? 6'hB : 6'h0;
assign EsubCode = 9'h0;

reg [`ms_2_ws_bus_wid - 1:0] ms_to_ws_bus_reg;

always @(posedge clk) begin
    if (ms_to_ws_valid && ws_allowin) begin
        ms_to_ws_bus_reg <= ms_to_ws_bus;
    end
end

assign {
        csr_signal,     //81
        ex,             //1
        ertn,           //1
            
        ws_gr_we,
        ws_dest,
        ws_final_result,
        ws_pc   
            } = ms_to_ws_bus_reg;

assign ws_to_id_bus = {
        ws_rf_we,   //38
        rf_we   ,  //37
        rf_waddr,  //36:32
        rf_wdata   //31:0
};

assign ws_ex_out = ex && ws_valid;

assign ws_rf_we = ws_gr_we & ws_valid;
assign ws_ready_go = 1'b1;
assign ws_allowin = (~ws_valid) | ws_ready_go;

always @(posedge clk ) begin
    if (reset) begin
        ws_valid <= 1'b0;
    end
    if (ws_ex_out || ws_ertn_flush)
        ws_valid <= 1'b0;
    else if (ws_allowin) begin
        ws_valid <= ms_to_ws_valid;
    end
end

assign rf_we    = ws_gr_we & ws_valid;
assign rf_waddr = ws_dest;
assign rf_wdata = (csrrd | csrwr | csrxchg) ? csr_rvalue : ws_final_result;

// debug info generate
assign debug_wb_pc       = ws_pc;
assign debug_wb_rf_we   = {4{rf_we}};
assign debug_wb_rf_wnum  = rf_waddr;
assign debug_wb_rf_wdata = rf_wdata;

endmodule